<?php

namespace App\Http\Controllers;

/**
 * 电子书解析类
 * Class EbookController
 * @package Admin\Controller
 */
class EbookAnalysisController
{

    //解压电子书
    public function getZipOriginalsize($filename, $path)
    {
        header("Content-type:text/html;charset=utf-8");
        //先判断待解压的文件是否存在
        if (!file_exists($path . $filename)) {
            die("文件 $filename 不存在！");
        }
        // $starttime = explode(' ',microtime()); //解压开始的时间

        //将文件名和路径转成windows系统默认的gb2312编码，否则将会读取不到
        $filename = iconv("utf-8", "gb2312", $filename);
        $path = iconv("utf-8", "gb2312", $path);
        //打开压缩包
        $resource = zip_open($path . $filename);
        $i = 1;
        //遍历读取压缩包里面的一个个文件
        $dir_resource = zip_read($resource);
        if ($dir_resource) {
            while ($dir_resource = zip_read($resource)) {
                //如果能打开则继续
                if (zip_entry_open($resource, $dir_resource)) {
                    //获取当前项目的名称,即压缩包里面当前对应的文件名
                    $file_name = zip_entry_name($dir_resource);
                    //解压文件统一放在一个新的文件夹下,以压缩文件的文件名做目录名
                    $new_filename = str_replace(['.epub', '.zip'], '', $filename);
                    $file_name = $path . $new_filename . '/' . $file_name;

                    //以最后一个“/”分割,再用字符串截取出路径部分
                    $file_path = substr($file_name, 0, strrpos($file_name, "/"));
                    //如果路径不存在，则创建一个目录，true表示可以创建多级目录
                    if (!is_dir($file_path)) {
                        mkdir($file_path, 0777, true);
                    }
                    //如果不是目录，则写入文件
                    if (!is_dir($file_name)) {
                        //读取这个文件
                        $file_size = zip_entry_filesize($dir_resource);
                        //最大读取6，如果文件过大，跳过解压，继续下一个
                        if ($file_size < (1024 * 1024 * 1024 * 2)) {
                            $file_content = zip_entry_read($dir_resource, $file_size);
                            file_put_contents($file_name, $file_content);
                        } else {
                            echo "<p> " . $i++ . " 此文件已被跳过，原因：文件过大， -> " . iconv("gb2312", "utf-8", $file_name) . " </p>";
                        }
                    }
                    //关闭当前
                    zip_entry_close($dir_resource);
                }
            }
            //关闭压缩包
            zip_close($resource);
            return $new_filename; //返回新建文件夹名称

            /*        $endtime = explode(' ',microtime()); //解压结束的时间
                $thistime = $endtime[0]+$endtime[1]-($starttime[0]+$starttime[1]);
                $thistime = round($thistime,3); //保留3为小数
                echo "<p>解压完毕！，本次解压花费：$thistime 秒。</p>";*/
        } else {
            return false;
        }
    }

    /**
     * 获取电子书的封面   ISBN  与出版时间  标题   作者
     * 解压后的 文件有3个   META-INF （固定）  OPS或者OEBPS （不固定）  minetype   （固定）
     *
     * 因为  资源全在   OPS或者OEBPS下，但是他又是不固定的，所以我们需要找规律，找到想要的资源路径
     * $path = 'D:/phpStudy/WWW/readshare/Uploads/ebook/2019-02-20/5c6d0d62f26e8'
     * 或$path = 'D:/phpStudy/WWW/readshare/Uploads/ebook/2019-02-20/5c6d0d62f26e8.epub';
     */
    public function getEbookCoverImg($path)
    {
        $news_path = explode('.', $path);
        $path = strpos($path, '.') ? reset($news_path) : $path;
        //判断文件是否存在  ,container,为  META-INF 下唯一文件
        $container_name = $path . '/META-INF/container.xml';
        $full_path = $this->getFullPath($container_name);
        //然后在打开刚才获取到的文件
        $content_opf_resource = file_get_contents($path . '/' . $full_path);
        //获取图片
        preg_match_all('~<item.*?media-type="image/jpeg".*?/>~', $content_opf_resource, $cover_arr); //因为有些电子书href和id位置不一致
        foreach ($cover_arr[0] as $key => $val) {
            if (strpos($val, 'cover') !== false || strpos($val, 'FM') !== false) {
                preg_match('~href="(.*?)"~', $val, $cover_img_arr);
                break; //获取到就不继续获取
            }
        }
        /* preg_match('~<dc:identifier.*?>(.*?)</dc:identifier>~' , $content_opf_resource , $isbn_arr);*/
        preg_match('~<dc:date.*?>(.*?)</dc:date>~', $content_opf_resource, $date_arr);

        //标题
        preg_match('~<dc:title.*?>(.*?)</dc:title>~', $content_opf_resource, $title_arr);
        //作者
        preg_match('~<dc:creator.*?>(.*?)</dc:creator>~', $content_opf_resource, $author_arr);

        $data = [];

        //$full_path 判断是否包含 / 斜线
        if (!empty($cover_img_arr)) {
            if (strpos($full_path, '/') !== false) {
                $full_path = explode('/', $full_path);
                $dir_name = reset($full_path);
                //获取图片路径
                $cover_img_arr  && $data['cover_img'] = $dir_name . '/' . $cover_img_arr[1];
            } else {
                $cover_img_arr  && $data['cover_img'] = $cover_img_arr[1];
            }
        }
        //  $isbn_arr  && $data['isbn'] = $isbn_arr[1];
        $date_arr  && $data['date'] = $date_arr[1];
        $title_arr  && $data['title'] = $title_arr[1];
        $author_arr  && $data['author'] = $author_arr[1];

        //返回图片路径
        return $data;
    }


    /**
     * 获取电子书名称 作者 及内容
     * $path = 'D:/phpStudy/WWW/readshare/Uploads/ebook/2019-02-20/123dasjkdnjajkj';
     * 或$path = 'D:/phpStudy/WWW/readshare/Uploads/ebook/2019-02-20/123dasjkdnjajkj.epub';
     * $file_name = 'ebook/2019-02-19/5c6bd330c9e78/';路径前半部分
     */
    public function getContent($path, $file_name)
    {
        $news_path = explode('.', $path);
        $path = strpos($path, '.') ? reset($news_path) : $path;
        $container_name = $path . '/META-INF/container.xml';
        $full_path = $this->getFullPath($container_name);

        //然后在打开刚才获取到的文件
        $content_opf_resource = file_get_contents($path . '/' . $full_path);

        //获取目录文件  ,获取目录文件
        preg_match('~<item.*?id="ncx".*?/>~', $content_opf_resource, $ncx_arr);

        preg_match('~href="(.*?)"~', $ncx_arr[0], $ncx_fb_arr);


        //$full_path 判断是否包含 / 斜线
        if (strpos($full_path, '/') !== false) {
            $news_full_path = explode('/', $full_path);
            $dir_name = reset($news_full_path);
            $toc_ncx_content = file_get_contents($path . '/' . $dir_name . '/' . $ncx_fb_arr[1]);

            $file_name =  $file_name . '/' . $dir_name; //增加一个路径
        } else {
            $toc_ncx_content = file_get_contents($path . '/' . $ncx_fb_arr[1]);
        }


        /*if(file_exists($path.'/'.$dir_name.'/toc.ncx')){
        $toc_ncx_content = file_get_contents($path.'/'.$dir_name.'/toc.ncx');
    }else if (file_exists($path.'/'.$dir_name.'/fb.ncx')){
        $toc_ncx_content = file_get_contents($path.'/'.$dir_name.'/fb.ncx');
    }else{
        die('获取电子书名称、作者路径错误');
    }*/
        $content_arr = $this->xmlstrToArray($toc_ncx_content);

        //获取名称
        $ebook_filename = isset($content_arr['docTitle']['text']) ? $content_arr['docTitle']['text'] : '';
        //获取作者
        $ebook_author = isset($content_arr['docAuthor']['text']) ? $content_arr['docAuthor']['text'] : '';

        $content_important_arr = $content_arr['navMap']['navPoint'];

        $data['ebook_filename'] = $ebook_filename;
        $data['ebook_author'] = $ebook_author;
        $data['content'] = $this->analysisContentArr($content_important_arr, $file_name); //$dir_name为 src需要拼接的部分
        return $data;
    }

    /**
     * 处理数据
     */
    public function analysisContentArr($content_important_arr, $file_name)
    {
        if (!isset($content_important_arr['navLabel'])) {
            foreach ($content_important_arr as $key => $val) {
                // dump($val);
                //判断数组中是否还有数组
                if (array_key_exists('navPoint', $val)) {
                    //证明还是一个数组
                    $data[$key]['navLabel'] = $val['navLabel']['text'];
                    $data[$key]['src'] = $file_name . '/' . $val['content']["@attributes"]['src'];
                    $data[$key]['id'] = $val["@attributes"]['id'];
                    $data[$key]['playOrder'] = $val["@attributes"]['playOrder'];
                    $data[$key]['child'] = $this->analysisContentArr($val['navPoint'], $file_name);
                } else {
                    $data[$key]['navLabel'] = $val['navLabel']['text'];
                    $data[$key]['src'] = $file_name . '/' . $val['content']["@attributes"]['src'];
                    $data[$key]['id'] = $val["@attributes"]['id'];
                    $data[$key]['playOrder'] = $val["@attributes"]['playOrder'];
                }
            }
        } else {
            //不存在，这不进入循环
            if (array_key_exists('navPoint', $content_important_arr)) {
                //证明还是一个数组
                $data[0]['navLabel'] = $content_important_arr['navLabel']['text'];
                $data[0]['src'] = $file_name . '/' . $content_important_arr['content']["@attributes"]['src'];
                $data[0]['id'] = $content_important_arr["@attributes"]['id'];
                $data[0]['playOrder'] = $content_important_arr["@attributes"]['playOrder'];
                $data[0]['child'] = $this->analysisContentArr($content_important_arr['navPoint'], $file_name);
            } else {
                $data[0]['navLabel'] = $content_important_arr['navLabel']['text'];
                $data[0]['src'] = $file_name . '/' . $content_important_arr['content']["@attributes"]['src'];
                $data[0]['id'] = $content_important_arr["@attributes"]['id'];
                $data[0]['playOrder'] = $content_important_arr["@attributes"]['playOrder'];
            }
        }

        return $data;
    }

    /**
     * xml转成数组
     */
    function xmlstrToArray($xmlstr)
    {
        $doc = new \DOMDocument();
        $doc->loadXML($xmlstr);
        return $this->domnodeToArray($doc->documentElement);
    }
    function domnodeToArray($node)
    {
        $output = array();
        switch ($node->nodeType) {
            case XML_CDATA_SECTION_NODE:
            case XML_TEXT_NODE:
                $output = trim($node->textContent);
                break;
            case XML_ELEMENT_NODE:
                for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
                    $child = $node->childNodes->item($i);
                    $v = $this->domnodeToArray($child);
                    if (isset($child->tagName)) {
                        $t = $child->tagName;
                        if (!isset($output[$t])) {
                            $output[$t] = array();
                        }
                        $output[$t][] = $v;
                    } elseif ($v) {
                        $output = (string) $v;
                    }
                }
                if (is_array($output)) {
                    if ($node->attributes->length) {
                        $a = array();
                        foreach ($node->attributes as $attrName => $attrNode) {
                            $a[$attrName] = (string) $attrNode->value;
                        }
                        $output['@attributes'] = $a;
                    }
                    foreach ($output as $t => $v) {
                        if (is_array($v) && count($v) == 1 && $t != '@attributes') {
                            $output[$t] = $v[0];
                        }
                    }
                }
                break;
        }
        return $output;
    }



    /**
     * 获取 container.xml  里面  <rootfile    full-path的值>
     * @param $container_name
     */
    public function getFullPath($container_name)
    {
        if (!file_exists($container_name)) {
            die("文件 META-INF或container.xml 文件不存在！");
        }
        //读取xml文件
        $container_resource = file_get_contents($container_name);
        //XML标签配置
        preg_match('~<rootfile full-path="(.*?)" media-type=".*?"/>~', $container_resource, $full_path_arr);
        if ($full_path_arr) {
            return $full_path_arr[1];
        } else {
            die('获取文件夹失败');
        }
    }
}
